/*
 * @Author: xiaosihan 
 * @Date: 2021-05-04 10:17:53 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2021-11-07 18:35:14
 */

import React from "react";
import * as THREE from "three";
import Mesh, { MeshProps } from "../Mesh/Mesh";
import Object3D from "../Object3D/Object3D";
import Object3DComponent, { Object3DComponentProps } from "../Object3D/Object3DComponent";
import { ReactThreeContext } from "../Renderer/Renderer";
import { Object3DEvent } from "../Renderer/type";
import TransitionColor from "../xrt_util/TransitionColor";
import THREEInstancedMesh, { THREEInstancedMeshItem } from "./THREEInstancedMesh";

export interface InstancedMeshProps extends MeshProps {

}

interface State { }

//实例模型 用于解决 超大数量的模型性能问题
export default class InstancedMesh extends Mesh<InstancedMeshProps, State> {

    constructor(props: InstancedMeshProps) {
        super(props);

        let name = this.getConstructorName();

        this.object3d = new (Function("THREEInstancedMesh", `
            return class ${name} extends THREEInstancedMesh {};
        `)(THREEInstancedMesh));
    }

    declare object3d: Object3D & THREEInstancedMesh;

    // 设置鼠标相关的事件
    setMouseEvent() {
        const { mouseEventMesh } = this.context;

        // 加入到鼠标拾取数组中
        if (!mouseEventMesh.includes(this.object3d)) {
            mouseEventMesh.push(this.object3d);
        }
    }

    render() {
        return (
            <ReactThreeContext.Provider
                value={{
                    ...this.context,
                    parent: this.object3d,
                    instancedMeshParent: this.object3d
                }}
            >
                {this.props.children}
            </ReactThreeContext.Provider >
        );
    }

}




export interface InstancedMeshItemProps extends Object3DComponentProps {

    color?: string; //-------------------------------- 颜色

}

interface State { }

//实例模型的子元素
export class InstancedMeshItem extends Object3DComponent<InstancedMeshItemProps, State> {
    constructor(props: InstancedMeshItemProps) {
        super(props);

        // 创建基础对象object3d;
        let name = this.getConstructorName();

        this.object3d = new (Function("THREEInstancedMeshItem", `
            return class ${name} extends THREEInstancedMeshItem {};
        `)(THREEInstancedMeshItem));

    }

    isInstancedMeshItem = true; // 实例成员数组对象

    declare object3d: Object3D & THREEInstancedMeshItem;

    Tcolor = new TransitionColor(this.props.color || "#fff");

    static Color = new THREE.Color;

    setTransColor() {
        const { bezier, duration = 500, color = "#fff" } = this.props;
        this.Tcolor.setBezier(bezier).setDuration(duration).set(color);
    }

    // 设置颜色
    setColor = () => {
        const { instancedMeshParent } = this.context;

        // 颜色
        if (instancedMeshParent && !this.Tcolor.isDone()) {
            const { r, g, b } = this.Tcolor.getJson();
            InstancedMeshItem.Color.setRGB(r, g, b);
            (instancedMeshParent as THREEInstancedMesh).setColorAtByItem(this.object3d, InstancedMeshItem.Color);
        } else {
            this.object3d.removeEventListener(Object3DEvent.BEFORE_RENDER, this.setColor);
        }

    }

    componentDidMount() {
        const { instancedMeshParent } = this.context;
        if (instancedMeshParent) {
            (instancedMeshParent as THREEInstancedMesh).addItem(this.object3d);
            this.setTransColor();
        }

        this.object3d.addEventListener(Object3DEvent.BEFORE_RENDER, this.setColor);
    }

    componentDidUpdate() {
        this.setTransColor();

        // 先取消在监听 避免重复监听
        this.object3d.removeEventListener(Object3DEvent.BEFORE_RENDER, this.setColor);
        this.object3d.addEventListener(Object3DEvent.BEFORE_RENDER, this.setColor);
    }

    componentWillUnmount() {
        const { instancedMeshParent } = this.context;
        if (instancedMeshParent) {
            (instancedMeshParent as THREEInstancedMesh).removeItem(this.object3d);
        }

        this.object3d.removeEventListener(Object3DEvent.BEFORE_RENDER, this.setColor);
    }
}